E) constexpr & Template Meta Programming

http://egloos.zum.com/sweeper/v/3147813
constexpr
constexpr는 일반화된 상수 표현식(Generalized constant expression을 사용할 수 있게 해주며,
일반화된 상수 표현식을 통해 변수나 함수, 생성자 함수에 대하여 컴파일 타임에 평가될 수 있도록 처리해 줄 수 있다.
- 변수
- 함수
- 생성자 함수
- 람다 함수(C++17부터)

constexpr 변수 또는 함수의 반환값은 반드시 LiteralType이어야 한다.
(LiteralType은 컴파일 타임에 레이아웃이 결정될 수 있는 타입)
- void
- 스칼라
- 참조(reference)

std::is_literal_type을 사용해서 확인 가능
    변수에서의 사용
const 변수의 초기화를 런타임까지 지연시킬 수 있는 반면, constexpr 변수는 컴파일 타임에 초기화 되어 있어야 함
constexpr flaot x=4.2f; // OK
constexpr float y{108.f}; // OK
constexpr int i; // error
int j=0;
constexpr int k=j+1; // error
constexpr 변수는 const 한정자를 암시한다.(변경 불가능)
함수에서의 사용
constexpr 함수 반환값은 아래의 제약을 따른다.
- 가상으로 재정의된 함수가 아니여야 함
- 반환값의 타입은 LiteralType이어야 함

함수에 constexpr를 붙일 경우, inline을 암시함
컴파일 타임에 평가하기 때문에, inline 함수들과 같이 컴파일 된다.
constexpr int factorial(int n){ // C++11/14
// C++11
// C++11
return n<1?:(n*factorial(n-1));
}
constexpr int factorial(int n){ // C++14
// C++14
int result=0;
// C++14
if(n<1=1) result=1;
else result=n*factorial(n-1);
return result;
}
constexpr 함수는 컴파일러에게 가능하다면, 컴파일 타임에 처리하지만
상황에 따라 런타임에 실행될 수도 있다.(inline도 동일함)

constexpr 함수 인자들이 constexpr 규칙에 부합하지 못하는 경우에는 컴파일 타임에 실행되지 않고 런타임에 실행
    런타임 실행 여부 테스트 템플릿
template <int N>
struct constN{
constN(void){ std::cout<<N<<'\n'; }
};
constexpr int factorial(int n){
return n<=1?1:(n*factorial(n-1));
}
int main(void){
constN<factorial(4)> out1;
int ab=4;
constN<factorial(ab)> out2; // error ab is not LiteralType
int cd=factorial(ab); //
//
return 0;
}
    상수화가 될 수 없는 문맥
constexpr int rand_short(void){
return rand()%65535; //error;
}
생성자 함수에서의 사용
LiteralType 클래스를 생성할 때, constexpr 생성자를 사용할 수 있다.
모든 생성자 함수의 매개변수들 역시 LiteralType이어야 하며,
어떤 클래스로부터 상속받지 않아야 한다.
class ConstString{
private:
const char* p=null;
std::size_t sz=0;
public:
template <std::size_t N>
constexpr ConstString(const char (&a)[N]): p(a), sz(N-1) {}
constexpr char operator[](std::size_t n) const{
return n<sz?p[n]:throw std::out_of_range("");
}
constexpr std::size_t size(void) const{ return sz; }
};
constexpr std::size_t CountLowercase(ConstString s, std::size_t n=0, std::size_t c=0){
return n==s.size()? c: s[n]>='a' && s[n]<='z'? CountLowercase(s, n+1, c+1): CountLowercase(s, n+1, c);
}
template <int N>
struct ConstN{
ConstN(void){
std::cout<<n<<'\n';
}
};
int main(void){
std::cout<<"Number of lowercase letters in \"Hello, world!\" is ";
ConstN<COuntLowercase("Hello, world!")> out;
return 0;
}